package org.example.utils.market.Store;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.catalina.Store;
import org.example.dao.dao.market.CStoreDao;
import org.example.dao.entity.market.CStore;
import org.example.exception.ServerErrorException;
import org.example.skytool.commom.IdWorker;
import org.example.skytool.commom.StringUtil;
import org.example.skytool.json.JackSonUtil;
import org.example.skytool.redis.CacheClient;
import org.example.skytool.redis.RedisUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import static org.example.skytool.redis.RedisConstants.*;

/**
 * @author xluo
 * @date 2023/11/9 8:00
 */
@Component
public class RedisStoreService {

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private CStoreDao cStoreDao;

    @Resource
    private IdWorker idWorker;

    @Resource
    private CacheClient cacheClient;

    public String getStoreVersionKey() {
        String key = MARKET_MOUDLE + MARKET_STORE_CONTROLLER + MARKET_STORE_VERSION_KIND;
        return key;
    }

    public String getStoreIdsKey(String version) {
        String key = MARKET_MOUDLE + MARKET_STORE_CONTROLLER + MARKET_STORE_TOTAL_KIND + version;
        return key;
    }

    public String getStoreContentKey(String storeId) {
        String key = MARKET_MOUDLE + MARKET_STORE_CONTROLLER + MARKET_STORE_CACHE_KIND + storeId;
        return key;
    }

    public String getStoreContentLock(String storeId) {
        String key = MARKET_MOUDLE + MARKET_STORE_CONTROLLER + MARKET_STORE_CACHE_KIND + storeId + ":lock";
        return key;
    }

    private String getCacheStoreVersionKey(String businessId) {
        String key = USER_MOUDLE + businessId + USER_OAA_CONTROLLER + USER_OAA_STOREVERSION_KIND;
        return key;
    }

    private String getCacheStoreKey(String businessId, String version) {
        String key = USER_MOUDLE + businessId + USER_OAA_CONTROLLER + USER_OAA_STORE_KIND + version;
        return key;
    }

    public IPage<CStore> getStoreList(Long businessId, Long limit, Long start) {
        return null;
    }

    public void setStoreIds(List<String> list, String version) {
        redisUtils.listRightAddAll(getStoreIdsKey(version), list.toArray(new String[0]));
    }

    public void delStoreIds(String version) {
        redisUtils.del(getStoreIdsKey(version));
    }

    /**
     * 构建所有店铺缓存
     */
    public void createStoreIds() {
        String version = redisUtils.stringGet(getStoreVersionKey());
        String newVersion = idWorker.nextId() + "";
        Long total = 0L;
        Long start = 1L;
        Long limit = 50L;
        Long count = 0L;
        do {
            List<String> result = new ArrayList<>();
            List<Long> ids = cStoreDao.getIds(limit, (start - 1) * limit);
            count = (long) ids.size();
            total += count;
            start ++;
            if (count != 0) {
                for (Long id : ids) {
                    result.add(id.toString());
                }
                setStoreIds(result, newVersion);
            }

        } while (limit.equals(count));

        redisUtils.stringSet(getStoreVersionKey(), newVersion);

        if (!StringUtil.isEmpty(version)) {
            delStoreIds(version);
        }

    }

    /**
     * 为商户构建商户店铺缓存
     */
    public void setCacheStoreIds(Long businessId) {
        String version = redisUtils.stringGet(getCacheStoreVersionKey(businessId.toString()));
        String newVersion = idWorker.nextId() + "";
        LambdaQueryWrapper<CStore> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(CStore::getBusinessId, businessId);
        Long start = 1L;
        Long limit = 50L;
        Long count = 0L;
        do {
            List<String> result = new ArrayList<>();
            Page<CStore> cStorePage = cStoreDao.selectPage(new Page<>(start, limit), lambdaQueryWrapper);
            List<CStore> records = cStorePage.getRecords();
            count = (long) records.size();
            start ++;
            if (count != 0) {
                for (CStore record : records) {
                    result.add(String.valueOf(record.getId()));
                }
                redisUtils.listRightAddAll(getCacheStoreKey(businessId.toString(), newVersion),
                        result.toArray(new String[0]));
            }
        } while (limit.equals(count));
        redisUtils.stringSet(getCacheStoreVersionKey(String.valueOf(businessId)), newVersion);
        //删除旧缓存
        if (!StringUtil.isEmpty(version)) {
            redisUtils.del(getCacheStoreKey(String.valueOf(businessId), version));
        }
    }

    /**
     * 获取店铺信息(用户)
     */
    public IPage<CStore> getCacheStoresForUsers (Integer limit, Integer start) {
        String version = redisUtils.stringGet(getStoreVersionKey());
        if (version == null) {
            throw new ServerErrorException("market store total version不存在");
        }
        List<String> ids = redisUtils.listGet(getStoreIdsKey(version), start - 1, limit);
        List<CStore> cacheStoresContent = getCacheStoresContent(ids);
        IPage<CStore> result = new Page<>(start, limit);
        result.setRecords(cacheStoresContent);
        result.setTotal(redisUtils.listGetSize(getStoreIdsKey(version)));
        return result;
    }

    /**
     * 获取店铺信息(商户)
     */
    public IPage<CStore> getCacheStoresForBusiness (Long businessId, Integer limit, Integer start) {
        String version = redisUtils.stringGet(getCacheStoreVersionKey(String.valueOf(businessId)));
        if (version == null) {
            throw new ServerErrorException("user oaa storeversion不存在");
        }
        List<String> ids = redisUtils.listGet(getCacheStoreKey(String.valueOf(businessId), version),
                start - 1, limit);
        List<CStore> cacheStoresContent = getCacheStoresContent(ids);
        IPage<CStore> result = new Page<>(start, limit);
        result.setRecords(cacheStoresContent);
        result.setTotal(redisUtils.listGetSize(getCacheStoreKey(String.valueOf(businessId), version)));
        return result;
    }

    /**
     * 批量获取店铺信息
     */
    public List<CStore> getCacheStoresContent(List<String> storeIds) {
        if (storeIds == null) {
            return null;
        }
        List<String> storeKeys = new ArrayList<>();
        for (String storeId : storeIds) {
            storeKeys.add(getStoreContentKey(storeId));
        }
        List<String> stores = redisUtils.stringMutiGet(storeKeys);
        List<CStore> results = new ArrayList<>();
        for (int i = 0; i < stores.size(); i++) {
            CStore cacheStore;
            if (stores.get(i) == null || Objects.equals(stores.get(i), "")) {
                cacheStore = getCacheStore(storeIds.get(i));
            } else {
                cacheStore = JackSonUtil.parse(CStore.class, stores.get(i));
            }
            results.add(cacheStore);
        }
        return results;
    }

    /**
     * 获取单个店铺信息
     */
    public CStore getCacheStore(String storeId) {

        String cacheKey = getStoreContentKey(storeId);
        Class<CStore> type = CStore.class;
        Map<String, Object> param = new HashMap<>();
        param.put("id", storeId);
        String lockKey = getStoreContentLock(storeId);

        Function<Map, CStore> dbFallback = params -> {
            Long id = Long.valueOf((String) params.get("id"));
            CStore cStore = cStoreDao.selectById(id);
            return cStore;
        };

        Long time = 30L;
        TimeUnit unit = TimeUnit.MINUTES;
        Long nullTtl = 30L;

        CStore result = cacheClient.queryString(cacheKey, type, param, lockKey, dbFallback, time, unit, nullTtl);

        return result;
    }

}
